package router

import (
	"context"
	"fmt"
	"net/http"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"github.com/spf13/viper"

	_ "gitee.com/jysense/gogofly/docs"
	"gitee.com/jysense/gogofly/global"
	"gitee.com/jysense/gogofly/middleware"

	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
)

type IFnRegistRoute = func(rgPublic *gin.RouterGroup, rgAuth *gin.RouterGroup)

var (
	gfnRoutes []IFnRegistRoute
)

func RegistRoute(fn IFnRegistRoute) {
	if fn == nil {
		return
	}

	gfnRoutes = append(gfnRoutes, fn)
}

func InitRouter() {

	ctx, cancelCtx := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer cancelCtx()

	// ==========================================================
	// = 初始化gin框架，并注册相关路由
	r := gin.Default()
	r.Use(middleware.Cors())

	rgPublic := r.Group("/api/v1/public")

	rgAuth := r.Group("/api/v1")

	rgAuth.Use(middleware.Auth())

	// 初始化基础平台的路由
	InitBasePlatformRoutes()

	// ==========================================================
	// = 注册自定义校验器
	registerCustValidator()

	// 开始注册系统各模块对应的路由信息
	for _, fnRegistRoute := range gfnRoutes {
		fnRegistRoute(rgPublic, rgAuth)
	}

	// = 集成swagger
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	stPort := viper.GetString("server.port")
	if stPort == "" {
		stPort = "8999"
	}

	server := &http.Server{
		Addr:    fmt.Sprintf(":%s", stPort),
		Handler: r,
	}

	go func() {
		global.Logger.Info(fmt.Sprintf("start server listen:%s", stPort))
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			// ==========================================================
			// = 记录日志
			global.Logger.Error(fmt.Sprintf("start server error:%s", err.Error()))
			return
		}
	}()

	<-ctx.Done()

	// ==========================================================
	// = 关闭server， 5s内未完成清理会直接退出应用
	ctx, cancelShutdown := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancelShutdown()

	if err := server.Shutdown(ctx); err != nil {
		global.Logger.Error(fmt.Sprintf("stop server error:%s", err.Error()))
	}
	global.Logger.Info("stop server success")
}

func InitBasePlatformRoutes() {
	InitUserRoutes()
	InitHostRoutes()
}

func registerCustValidator() {
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		_ = v.RegisterValidation("first_is_a", func(fl validator.FieldLevel) bool {
			if value, ok := fl.Field().Interface().(string); ok {
				if value != "" && 0 == strings.Index(value, "a") {
					return true
				}
			}
			return false
		})
	}
}
